/*
 * 人人信用管理有限公司版权所有.
 * 
 * @Description:
 * 
 * @author: liyuliang
 * 
 * @date: 20 Apr 2017 10:44:16 am
 * 
 * 注意：本内容仅限于人人信用管理有限公司内部传阅，禁止外泄以及用于其他的商业目的.
 */

package com.rrx360.common.web;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;

import org.apache.commons.lang.ArrayUtils;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.SerializeWriter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.rrx360.common.context.ActionContext;
import com.rrx360.common.context.ActionContextKey;

public class JsonHttpMessageConverter extends AbstractHttpMessageConverter<Object> {

  public static final Charset UTF8 = Charset.forName("UTF-8");

  private Charset charset = UTF8;

  private SerializerFeature[] onFeatures = new SerializerFeature[] {
      SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat,
      SerializerFeature.DisableCircularReferenceDetect};

  // private SerializerFeature[] offFeatures = new
  // SerializerFeature[]{SerializerFeature.WriteEnumUsingName,};
  private SerializerFeature[] offFeatures = new SerializerFeature[] {};

  private String[] excludeClazz;

  public JsonHttpMessageConverter() {
    super(new MediaType("application", "json", UTF8), new MediaType("application", "*+json", UTF8));
  }

  @Override
  protected boolean supports(Class<?> clazz) {
    if (excludeClazz != null) {
      String clazzName = clazz.getName();
      return !ArrayUtils.contains(excludeClazz, clazzName);
    }
    return true;
  }

  public Charset getCharset() {
    return this.charset;
  }

  public void setCharset(Charset charset) {
    this.charset = charset;
  }


  public SerializerFeature[] getOnFeatures() {
    return onFeatures;
  }

  public void setOnFeatures(SerializerFeature[] onFeatures) {
    this.onFeatures = onFeatures;
  }

  public SerializerFeature[] getOffFeatures() {
    return offFeatures;
  }

  public void setOffFeatures(SerializerFeature[] offFeatures) {
    this.offFeatures = offFeatures;
  }

  @Override
  protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage)
      throws IOException, HttpMessageNotReadableException {

    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    InputStream in = inputMessage.getBody();

    byte[] buf = new byte[1024];
    for (;;) {
      int len = in.read(buf);
      if (len == -1) {
        break;
      }

      if (len > 0) {
        baos.write(buf, 0, len);
      }
    }

    byte[] bytes = baos.toByteArray();
    if (logger.isInfoEnabled()) {
      logger.info("JSON input:" + new String(bytes, charset));
    }
    return JSON.parseObject(bytes, 0, bytes.length, charset.newDecoder(), clazz);
  }

  @Override
  protected void writeInternal(Object obj, HttpOutputMessage outputMessage)
      throws IOException, HttpMessageNotWritableException {

    OutputStream out = outputMessage.getBody();
    SerializeWriter writer = new SerializeWriter();
    String text = null;
    try {
      JSONSerializer serializer = new JSONSerializer(writer);
      // on features
      SerializerFeature[] cfgOnFeatures = ActionContext.get(ActionContextKey.JSON_HTTP_ON_CFG);
      if (cfgOnFeatures == null) {
        cfgOnFeatures = onFeatures;
      }
      for (SerializerFeature feature : cfgOnFeatures) {
        serializer.config(feature, true);
      }

      // off features
      SerializerFeature[] cfgOffFeatures = ActionContext.get(ActionContextKey.JSON_HTTP_OFF_CFG);
      if (cfgOffFeatures == null) {
        cfgOffFeatures = offFeatures;
      }

      for (SerializerFeature feature : cfgOffFeatures) {
        serializer.config(feature, false);
      }

      serializer.write(obj);

      text = writer.toString();
    } finally {
      writer.close();
    }


    if (logger.isInfoEnabled()) {
      logger.info("JSON output:" + text);
    }
    byte[] bytes = text.getBytes(charset);
    out.write(bytes);
  }

  public String[] getExcludeClazz() {
    return excludeClazz;
  }

  public void setExcludeClazz(String[] excludeClazz) {
    this.excludeClazz = excludeClazz;
  }



}
